package com.vision.sales.check.cl.ui;

import static com.vision.sales.cl.SalesServices.checkSvc;

import java.util.ArrayList;
import java.util.List;

import com.allen_sauer.gwt.log.client.Log;
import com.google.gwt.core.client.GWT;
import com.google.gwt.editor.client.Editor;
import com.google.gwt.editor.client.SimpleBeanEditorDriver;
import com.google.gwt.i18n.client.NumberFormat;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiFactory;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.Widget;
import com.sencha.gxt.core.client.Style.SelectionMode;
import com.sencha.gxt.data.client.loader.RpcProxy;
import com.sencha.gxt.data.shared.ListStore;
import com.sencha.gxt.data.shared.loader.LoadResultListStoreBinding;
import com.sencha.gxt.data.shared.loader.PagingLoadConfig;
import com.sencha.gxt.data.shared.loader.PagingLoadResult;
import com.sencha.gxt.data.shared.loader.PagingLoader;
import com.sencha.gxt.widget.core.client.TabItemConfig;
import com.sencha.gxt.widget.core.client.button.TextButton;
import com.sencha.gxt.widget.core.client.container.VerticalLayoutContainer;
import com.sencha.gxt.widget.core.client.event.HideEvent;
import com.sencha.gxt.widget.core.client.event.ParseErrorEvent;
import com.sencha.gxt.widget.core.client.event.SelectEvent;
import com.sencha.gxt.widget.core.client.form.DateField;
import com.sencha.gxt.widget.core.client.form.NumberField;
import com.sencha.gxt.widget.core.client.form.NumberPropertyEditor;
import com.sencha.gxt.widget.core.client.form.NumberPropertyEditor.DoublePropertyEditor;
import com.sencha.gxt.widget.core.client.form.TextArea;
import com.sencha.gxt.widget.core.client.form.TextField;
import com.sencha.gxt.widget.core.client.grid.ColumnConfig;
import com.sencha.gxt.widget.core.client.grid.ColumnModel;
import com.sencha.gxt.widget.core.client.grid.Grid;
import com.sencha.gxt.widget.core.client.grid.GridView;
import com.sencha.gxt.widget.core.client.info.Info;
import com.sencha.gxt.widget.core.client.selection.SelectionChangedEvent;
import com.sencha.gxt.widget.core.client.selection.SelectionChangedEvent.SelectionChangedHandler;
import com.sencha.gxt.widget.core.client.toolbar.PagingToolBar;
import com.vision.core.cl.BaseModule;
import com.vision.core.cl.Callback;
import com.vision.core.cl.event.CreatedEvent;
import com.vision.core.cl.event.CreatedEvent.CreationHandler;
import com.vision.core.cl.ui.ConfirmDialogHandler;
import com.vision.core.cl.ui.TabItemPanel;
import com.vision.core.cl.ui.UI;
import com.vision.core.cl.ui.component.BasicGridView;
import com.vision.sales.cl.SalesServices;
import com.vision.sales.cl.SalesTasks;
import com.vision.sales.cl.data.CheckProperties;
import com.vision.sales.cl.event.CheckCreatedEvent;
import com.vision.sales.cl.resource.SalesResources;
import com.vision.sales.cl.ui.UIConstants;
import com.vision.sales.cl.ui.component.TransactionLoadConfig;
import com.vision.sales.cm.db.data.Check;

public class ChecksPanel extends TabItemPanel implements Editor<Check> {

	interface Binder extends UiBinder<Widget, ChecksPanel> {
	}

	private static final Binder binder = GWT.create(Binder.class);
	
	@UiField VerticalLayoutContainer mainPanel;
	
	// Ignored by the form driver since these are not fields in the Check
	@Ignore @UiField TextButton refreshBtn;
//	@Ignore @UiField TextButton addBtn;
//	@Ignore @UiField TextButton deleteBtn;
	
	@UiField Grid<Check> grid;
	@UiField PagingToolBar pagingToolbar;
	PagingLoader<PagingLoadConfig, PagingLoadResult<Check>> loader;
	
	// Form fields that are bound by the form driver to the fields in the Check class.
	// The name of these form fields must match the name of the field in the Check class.
	@UiField TextField bank;
	@UiField TextField checkNo;
	@UiField DateField checkDate;
	@UiField NumberField<Double> amount;
	@UiField DateField dateDeposited;
	@UiField DateField dateCleared;
	@UiField TextArea remarks;
	
	@UiField(provided = true)
	NumberPropertyEditor<Double> doublePropertyEditor = new DoublePropertyEditor();
	
	@UiField(provided = true)
	NumberFormat numberFormat = NumberFormat.getFormat("0.00");
	
	// Ignored by the form driver since these are not fields in the Check
	@Ignore @UiField TextButton saveBtn;
	@Ignore @UiField TextButton cancelBtn;
	
	// Interface used to bind the form fields to the Check fields
	interface CheckDriver extends SimpleBeanEditorDriver<Check, ChecksPanel> { }
	
	// Instance of the CheckDriver interface
	private CheckDriver driver = GWT.create(CheckDriver.class);
	
	// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	
	public ChecksPanel() {
		// Global Handlers -- should be registered only once
		BaseModule.addHandler(CheckCreatedEvent.TYPE, new CreationHandler<Check>() {
			@Override
			public void onCreated(CreatedEvent<Check> e) {
				grid.getStore().add(e.getObject());
			}
		});
		
		setWidget(binder.createAndBindUi(this));
		
		// Initialize loaders
		RpcProxy<PagingLoadConfig, PagingLoadResult<Check>> proxy = new RpcProxy<PagingLoadConfig, PagingLoadResult<Check>>() {
		    @Override
		    public void load(PagingLoadConfig loadConfig, AsyncCallback<PagingLoadResult<Check>> callback) {
		    	TransactionLoadConfig tConfig = new TransactionLoadConfig(loadConfig);
		    	SalesServices.checkSvc().getList(tConfig, callback);
		    }
	    };
	    
	    loader = new PagingLoader<PagingLoadConfig, PagingLoadResult<Check>>(proxy);
        loader.addLoadHandler(new LoadResultListStoreBinding<PagingLoadConfig, Check, PagingLoadResult<Check>>(grid.getStore()));
        
        grid.setLoader(loader);
        grid.setLoadMask(true);
		
		pagingToolbar.bind(loader);
		
		// Initialize the driver, used to run the form editor
		driver.initialize(this);
		
		checkDate.setPropertyEditor(UI.datePropertyEditor());
		dateDeposited.setPropertyEditor(UI.datePropertyEditor());
		dateCleared.setPropertyEditor(UI.datePropertyEditor());
	}
		
	// UiFactory Methods %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

	/**
	 * Used to create the 'grid' field in the XML file. 
	 * 
	 * @return
	 */
	@UiFactory
	Grid<Check> initializeGrid() {
		List<ColumnConfig<Check, ?>> columns = new ArrayList<ColumnConfig<Check, ?>>();

		columns.add(UI.column(CheckProperties.INSTANCE.bank(), UIConstants.CODE_COL_WIDTH, "Bank"));
		columns.add(UI.column(CheckProperties.INSTANCE.checkNo(), UIConstants.CODE_COL_WIDTH, "Check No."));
		columns.add(UI.column(CheckProperties.INSTANCE.checkDate(), UIConstants.CODE_COL_WIDTH, "Check Date", UI.dateCell()));
		columns.add(UI.column(CheckProperties.INSTANCE.amount(), UIConstants.NAME_COL_WIDTH, "Amount", UI.decimalCell(), HasHorizontalAlignment.ALIGN_RIGHT));
		columns.add(UI.column(CheckProperties.INSTANCE.dateCleared(), UIConstants.CODE_COL_WIDTH, "Date Cleared", UI.dateCell()));
		ColumnConfig<Check, String> column = UI.column(CheckProperties.INSTANCE.remarks(), UIConstants.CODE_COL_WIDTH, "Remarks");
		columns.add(column);
		
		ColumnModel<Check> cm = new ColumnModel<Check>(columns);

		final Grid<Check> grid = new Grid<Check>(new ListStore<Check>(CheckProperties.INSTANCE.key()), cm);
		grid.setAllowTextSelection(false);
		grid.setHeight(300);
		grid.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
		
		GridView<Check> view = new BasicGridView<Check>();
		view.setEmptyText("There are no checks to display.");
		view.setAutoExpandColumn(column);
		grid.setView(view);
		
		// Add a listener to the grid
		grid.getSelectionModel().addSelectionChangedHandler(new SelectionChangedHandler<Check>() {
			@Override
			public void onSelectionChanged(SelectionChangedEvent<Check> event) {
				final Check check = grid.getSelectionModel().getSelectedItem();
				if (check == null)
					return;
				
				if (driver.isDirty()) { // If there are unsaved changes in the form
					UI.confirm("Unsaved Changes", "There are unsaved changes. Would you like to continue loading?",
						new ConfirmDialogHandler() {
							@Override
							public void onYes(HideEvent event) {
								edit(check);
							}
							
							public void onCancel(HideEvent event) {
								// just close the message box
							}
							
							public void onNo(HideEvent event) {
								// previously selected item should remain selected 
							}
						}
					);
				} else {
					edit(check);
				}
			}
		});
		
		return grid;
	}
	
	// Logic %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	
	/**
	 * Loads <tt>check</tt> into the form editor.
	 * 
	 * @param check
	 */
	private void edit(final Check check) {
		driver.edit(check);
		
		saveBtn.setEnabled(check != null);
		cancelBtn.setEnabled(check != null);
	}
	
	// Listeners %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	
	// Called when the 'Refresh' button is clicked
	@UiHandler("refreshBtn")
	void refreshClicked(SelectEvent e) {
		loadData();
	}
	
//	// Called when the 'Add' button is clicked
//	@UiHandler("addBtn")
//	void addClicked(SelectEvent e) {
//		BaseModule.visit(SalesTasks.ADD_CHECK);
//	}
//	
//	// Called when the 'Delete' button is clicked
//	@UiHandler("deleteBtn")
//	void deleteClicked(SelectEvent e) {
//		final Check selected = grid.getSelectionModel().getSelectedItem();
//		if (selected == null)
//			return;
//		
//		UI.confirm("Confirm Delete", "Are you sure you want to delete '" + selected.getCheckNo() + "'?",
//			new ConfirmDialogHandler() {
//				@Override
//				public void onYes(HideEvent event) {
//					UI.mask(mainPanel, "Deleting " + selected.getCheckNo() + "...");
//					checkSvc().delete(selected, new Callback<Check>(mainPanel) {
//						@Override
//						protected void handleSuccess(Check result) {
//							grid.getStore().remove(result);
//							
//							// Clear the form editor if necessary
//							Check inEditor = driver.flush();
//							if (inEditor != null && inEditor.getCheckNo().equals(result.getCheckNo()))
//								edit(null);
//						}
//					});
//				}
//			}
//		);
//	}
	
	// Called when the 'Save' button is clicked
	@UiHandler("saveBtn")
	void saveClicked(SelectEvent e) {
		Check check = driver.flush();
		if (driver.hasErrors())
			return;
		
		UI.mask(mainPanel, "Updating checks...");
		checkSvc().update(check, new Callback<Check>(mainPanel) {
			@Override
			protected void handleSuccess(Check result) {
				grid.getStore().update(result);
				edit(result);
			}
		});
	}
	
	// Called when the 'Cancel' button is clicked
	@UiHandler("cancelBtn")
	void cancelClicked(SelectEvent e) {
		edit(null);
	}
	 
	// ITabItemPanel Methods %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	
	@Override
	public String getPanelId() {
		return SalesTasks.CHECKS.getId();
	}
	
	@Override
	public TabItemConfig getConfig() {
		if (config == null) {
			config = new TabItemConfig("Checks", true);
			config.setIcon(SalesResources.INSTANCE.checks());
		}
		return config;
	}
	@Override
	public void loadData() {
		Log.debug("Loading checks...");
		loader.load();
		edit(null);
	}

	@UiHandler("checkDate")
	public void onCheckDateParseError(ParseErrorEvent event) {
		Info.display("Parse Error", event.getErrorValue() + " could not be parsed as a date");
	}
	
	@UiHandler("dateDeposited")
	public void onDateDepositedParseError(ParseErrorEvent event) {
		Info.display("Parse Error", event.getErrorValue() + " could not be parsed as a date");
	}
	
	@UiHandler("dateCleared")
	public void onDateClearedParseError(ParseErrorEvent event) {
		Info.display("Parse Error", event.getErrorValue() + " could not be parsed as a date");
	}
	
}
